package session.stateless;

import entity.OwnerEntity;
import entity.UserAccessRightsEntity;
import entity.StaffAccountEntity;
import entity.StaffEntity;
import entity.StakeholderEntity;
import entity.TouristAccountEntity;
import entity.UserRoleAccessRightsEntity;
import entity.UserRoleEntity;
import exception.ExistException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Properties;
import javax.ejb.EJB;
import javax.ejb.EJBException;
import javax.ejb.Remove;
import javax.ejb.Stateless;
import javax.mail.Message;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import util.entityhelper.StaffAccountState;
import util.enumeration.AccessRight;
import util.enumeration.Country;
import util.enumeration.Department;
import util.enumeration.Gender;
import util.enumeration.JobPosition;
import util.enumeration.UserRoleType;
import util.generator.PasswordGenerator;
import util.mailhelper.SMTPAuthenticator;

/**
 *
 * @author AdminNUS
 */
@Stateless
public class StaffAccountSessionBean {

    @PersistenceContext
    EntityManager em;
    @EJB
    private MessageSessionBean messageSession;
    private String selectedLocale;
    private StaffEntity staffEntity;
    private StaffAccountEntity staffAccountEntity;
    private UserRoleEntity userRoleEntity;
    // EXCEPTION
    private SystemMessagesBean systemMessages;

    /** Creates a new instance of StaffAccountSessionBean */
    public StaffAccountSessionBean() {
        systemMessages = new SystemMessagesBean();
    }

    public void setSelectedLocale(String locale) {
        this.selectedLocale = locale;
    }

    public void createStaffAccount(String username, // username = primary email
            String lastName, String firstName,
            Gender gender, Date birthdate,
            Country country, String locale,
            String email, String emailSecondary,
            Department department, JobPosition jobPosition, UserRoleType userRoleType,
            Date joinDate, List<AccessRight> userAccessRights) throws ExistException {
        
        staffEntity = null;
        staffAccountEntity = null;
        // tourist user account entity does not exist;
        if (staffAccountEntity == null && staffEntity == null) {

            staffAccountEntity = new StaffAccountEntity();
            staffEntity = new StaffEntity();
            // auto get system time for registration date
            Calendar cal = Calendar.getInstance();
            Date creationDate = cal.getTime();
            // access rights
            List<UserAccessRightsEntity> newUserAccessRights = new ArrayList<UserAccessRightsEntity>();
            for (AccessRight ar : userAccessRights) {
                UserAccessRightsEntity newUserAccessRight = new UserAccessRightsEntity();
                newUserAccessRight.setAccessRight(ar);
                newUserAccessRights.add(newUserAccessRight);
            }
            // password is auto-generated from PasswordGenerator
            PasswordGenerator generator = new PasswordGenerator();
            // assume min length is 6
            String password = generator.generatePassword(6);

            List<UserRoleAccessRightsEntity> newUserRoleAccessRights = new ArrayList<UserRoleAccessRightsEntity>();
            for (AccessRight ar : userAccessRights) {
                UserRoleAccessRightsEntity newUserRoleAccessRight = new UserRoleAccessRightsEntity();
                newUserRoleAccessRight.setAccessRight(ar);
                newUserRoleAccessRights.add(newUserRoleAccessRight);
            }
            userRoleEntity = new UserRoleEntity();
            userRoleEntity.setUserRoleAccessRights(newUserRoleAccessRights);
            userRoleEntity.setUserRoleType(userRoleType);
            em.persist(userRoleEntity);

            staffEntity.create(lastName, firstName, gender, birthdate, country, locale, email, emailSecondary, department, jobPosition, joinDate);
            staffAccountEntity.create(username, password, creationDate, null);
            staffAccountEntity.setUserAccessRights(newUserAccessRights);
            staffAccountEntity.setActivationStatus(true);

            staffAccountEntity.setUserRole(userRoleEntity);

            staffAccountEntity.setStaff(staffEntity);
            em.persist(staffAccountEntity);

            System.out.println("creating new inbox....");
            OwnerEntity newUser = new OwnerEntity();
            newUser.setName(username);
            newUser.setStaff(true);
            newUser.setTourist(false);
            newUser.setStakeholder(false);
            messageSession.createMailbox(newUser);
            sendEmail(username, password, email);
        } else {
            // EXCEPTION
            throw new ExistException(systemMessages.getSystemMessage("STAFF_ACCT_EXISTS", selectedLocale));
        }
    }

    private void sendEmail(String username, String password, String email) {
        String emailServerName = "smtp.gmail.com";
        String emailFromAddress = "TCube Staff ADMIN<auhiew@gmail.com>";
        String toEmailAddress = email;
        String mailer = "JavaMailer";
        String subject = "";

        try {
            Properties props = new Properties();
            //props.put("mail.smtp.host", "smtp.gmail.com");
            props.put("mail.smtp.host", emailServerName);
            props.put("mail.smtp.socketFactory.port", "465");
            props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
            props.put("mail.smtp.auth", "true");
            props.put("mail.smtp.port", "465");
            props.put("mail.smtp.starttls.enable", "true");
            props.put("mail.smtp.debug", "true");
            javax.mail.Authenticator auth = new SMTPAuthenticator();

            Session session = Session.getInstance(props, auth);
            session.setDebug(true);
            //Message msg = new MimeMessage(session);
            MimeMessage msg = new MimeMessage(session);
            if (msg != null) {
                msg.setFrom(InternetAddress.parse(emailFromAddress, false)[0]);
                msg.setRecipients(Message.RecipientType.TO, InternetAddress.parse(toEmailAddress, false));
                subject = systemMessages.getSystemMessage("STAFF_REGISTER_MSG_TCUBE_ACCT_MSG", selectedLocale);
                msg.setSubject(subject, "UTF-8");

                String passwordMsg1 = systemMessages.getSystemMessage("STAFF_REGISTER_MSG_TCUBE_ACCT_MSG", selectedLocale);
                String passwordMsg2 = systemMessages.getSystemMessage("STAFF_REGISTER_LBL_USERNAME", selectedLocale);
                String passwordMsg3 = systemMessages.getSystemMessage("STAFF_REGISTER_LBL_PASSWORD", selectedLocale);
                String passwordMsg4 = systemMessages.getSystemMessage("STAFF_REGISTER_MSG_KEEP_SECURED", selectedLocale);
                String passwordMsg5 = systemMessages.getSystemMessage("STAFF_PASSWORD_MSG_3", selectedLocale);
                String messageText = passwordMsg1 + "\n\n"
                        + passwordMsg2 + " " + username + "\n"
                        + passwordMsg3 + " " + password + "\n\n"
                        + passwordMsg4 + "\n\n" + passwordMsg5;
                msg.setText(messageText, "UTF-8");
                msg.setHeader("Content-Type", "text/plain; charset=UTF-8");
                Date timeStamp = new Date();
                msg.setSentDate(timeStamp);
                Transport.send(msg);
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new EJBException(e.getMessage());
        }
    }

//    @Override
//    public void updateStaffAccountForSuperAdmin(Long staffAccountId, List<AccessRightsEntity> accessRights) throws ExistException {
//        // find account in persistence context
//        staffAccountEntity = em.find(StaffAccountEntity.class, staffAccountId);
//        
//        // tourist user account entity does not exist;
//        if (staffAccountEntity == null) {
//            // EXCEPTION
//            throw new ExistException(systemMessages.getSystemMessage("STAFF_ACCT_DOES_NOT_EXIST", selectedLocale));
//        }
//        else {
////            List<AccessRightsEntity> newAccessRights = new ArrayList<AccessRightsEntity>;
////            // reset access rights
////            for (UserAccessRightsEntity ar : accessRights) {
////                UserAccessRightsEntity newAccessRight = new UserAccessRightsEntity();
////                newAccessRight.setAccessRight(ar.getAccessRight());
////                newAccessRights.add(newAccessRight);
////            }
////            staffAccountEntity.getAccessRights().clear();
////            staffAccountEntity.setAccessRights(newAccessRights);
////            
////            em.persist(staffAccountEntity);
////            em.flush();
//        }
//    }
    public void updateStaffAccount(Long staffAccountId, String newPassword) throws ExistException {
        // find account in persistence context
        staffAccountEntity = em.find(StaffAccountEntity.class, staffAccountId);

        // tourist user account entity does not exist;
        if (staffAccountEntity == null) {
            // EXCEPTION
            throw new ExistException(systemMessages.getSystemMessage("STAFF_ACCT_DOES_NOT_EXIST", selectedLocale));
        } else {
            // check and update password and password change date fields
            String password = staffAccountEntity.getPassword();
            Date passwordChangeDate = staffAccountEntity.getPasswordChangeDate();
            if (!password.equals(newPassword)) {
                // auto get system time for registration date
                Calendar cal = Calendar.getInstance();
                passwordChangeDate = cal.getTime();
            }
            staffAccountEntity.update(newPassword, passwordChangeDate);

            em.persist(staffAccountEntity);
            em.flush();
        }
    }

    public void updateStaffForSuperAdmin(Long staffId, Country country, String locale, String email, String emailSecondary, Department department, JobPosition jobPosition) throws ExistException {
        // find tourist in persistence context
        staffEntity = em.find(StaffEntity.class, staffId);

        // tourist entity does not exist;
        if (staffEntity == null) {
            // EXCEPTION
            throw new ExistException(systemMessages.getSystemMessage("STAFF_ACCT_DOES_NOT_EXIST", selectedLocale));
        } else {
            staffEntity.update(country, locale, email, emailSecondary, department, jobPosition);
            em.persist(staffEntity);
            em.flush();
        }
    }

    public void updateStaff(Long staffId, Country country, String locale, String emailSecondary) throws ExistException {
        // find tourist in persistence context
        staffEntity = em.find(StaffEntity.class, staffId);

        // tourist entity does not exist;
        if (staffEntity == null) {
            // EXCEPTION
            throw new ExistException(systemMessages.getSystemMessage("STAFF_ACCT_DOES_NOT_EXIST", selectedLocale));
        } else {
            staffEntity.update(country, locale, emailSecondary);
            em.persist(staffEntity);
            em.flush();
        }
    }

    public void changeInitialPassword(Long staffAccountId, String newPassword) throws ExistException {
        // find account in persistence context
        staffAccountEntity = em.find(StaffAccountEntity.class, staffAccountId);

        // tourist user account entity does not exist;
        if (staffAccountEntity == null) {
            // EXCEPTION
            throw new ExistException(systemMessages.getSystemMessage("STAFF_ACCT_DOES_NOT_EXIST", selectedLocale));
        } else {
            // update password and password change date fields
            // auto get system time for registration date
            Calendar cal = Calendar.getInstance();
            Date passwordChangeDate = cal.getTime();

            staffAccountEntity.update(newPassword, passwordChangeDate);
            em.persist(staffAccountEntity);
            em.flush();
        }
    }

    public StaffAccountState getStaffAccountByID(Long staffUserAccountId) throws ExistException {
        StaffAccountState staffUserAccountState = null;

//        StaffAccountEntity staffAccount = em.find(StaffAccountEntity.class, staffUserAccountId);

        // find account id
        Query q = em.createQuery("SELECT a FROM StaffAcct a WHERE a.id = :accId");
        q.setParameter("accId", staffUserAccountId);

        if (q.getResultList().isEmpty()) {
//        if (staffAccount == null) {
            // show exception message using SystemMessage bean
            throw new ExistException(systemMessages.getSystemMessage("STAFF_ACCT_DOES_NOT_EXIST", selectedLocale));
        } else {
            StaffAccountEntity staffAccount = (StaffAccountEntity) q.getSingleResult();
            staffUserAccountState = new StaffAccountState(
                    staffAccount.getId(),
                    staffAccount.getUsername(),
                    staffAccount.getPassword(),
                    staffAccount.getCreationDate(),
                    staffAccount.getPasswordChangeDate(),
                    staffAccount.getActivationStatus(),
                    staffAccount.getUserAccessRights(),
                    staffAccount.getStaff(),
                    staffAccount.getUserRole());
        }
        return staffUserAccountState;
    }

    public StaffAccountState getStaffAccountByUsername(String username) // is primary email..
            throws ExistException {
        StaffAccountState staffAccountState = null;

        // find username
        Query q = em.createQuery("SELECT a FROM StaffAcct a WHERE a.username = :uname");
        q.setParameter("uname", username);

        // result has nothing...
        if (q.getResultList().isEmpty()) {
            // show exception message using SystemMessage bean
            throw new ExistException(systemMessages.getSystemMessage("STAFF_ACCT_DOES_NOT_EXIST", selectedLocale));
        } // if result has something...
        else {
            StaffAccountEntity a = (StaffAccountEntity) q.getSingleResult();
            System.out.println(a.getUsername() + "" + a.getPassword());
            staffAccountState = new StaffAccountState(
                    a.getId(),
                    a.getUsername(),
                    a.getPassword(),
                    a.getCreationDate(),
                    a.getPasswordChangeDate(),
                    a.getActivationStatus(),
                    a.getUserAccessRights(),
                    a.getStaff(),
                    a.getUserRole());
        }
        return staffAccountState;
    }

    public StaffAccountState getStaffAccountByEmail(String email) // is primary email..
            throws ExistException {
        StaffAccountState staffAccountState = null;

        // find username
        Query q = em.createQuery("SELECT a FROM StaffAcct a WHERE a.email = :emailInput");
        q.setParameter("emailInput", email);

        // result has nothing...
        if (q.getResultList().isEmpty()) {
            // show exception message using SystemMessage bean
            throw new ExistException(systemMessages.getSystemMessage("STAFF_ACCT_DOES_NOT_EXIST", selectedLocale));
        } // if result has something...
        else {
            StaffAccountEntity a = (StaffAccountEntity) q.getSingleResult();
            System.out.println(a.getUsername() + "" + a.getPassword());
            staffAccountState = new StaffAccountState(
                    a.getId(),
                    a.getUsername(),
                    a.getPassword(),
                    a.getCreationDate(),
                    a.getPasswordChangeDate(),
                    a.getActivationStatus(),
                    a.getUserAccessRights(),
                    a.getStaff(),
                    a.getUserRole());
        }
        return staffAccountState;
    }

//    public List<StaffAccountState> getTCubeAccountList() {
//        List<StaffAccountState> TCubeList = new ArrayList();
//        System.out.println("TCubeSesion1");
//
//        Query query = em.createQuery("SELECT a FROM StaffAcct a");
//        List<StaffAccountState> accountList = query.getResultList();
//        System.out.println("Size: " + accountList.size());
//        StaffAccountState t = null;
//        for (int i = 0; i < accountList.size(); i++) {
//            if (accountList.get(i).getClass().getName().equalsIgnoreCase("entity.StaffAcct")) {
//                t = (StaffAccountState) query.getSingleResult();
//                TCubeList.add(t);
//            }
//        }
//        return TCubeList;
//    }
    public void updateStatus(StaffAccountState user) {
        StaffAccountEntity s = em.find(StaffAccountEntity.class, user.getId());
        if (s != null) {
            s.setActivationStatus(user.getStatus());
            em.persist(s);
            em.flush();
        }
    }

    public void inactivateAccount(StaffAccountState user) throws ExistException {
        TouristAccountEntity s = em.find(TouristAccountEntity.class, user.getId());
        if (s != null) {
            s.setActivationStatus(user.getStatus());
            em.persist(s);
            em.flush();
        }
    }

//    @Override
//    public void inactivateAccount(StaffAccountState user) throws ExistException {
//        TouristAccountEntity s = em.find(TouristAccountEntity.class, user.getId());
//        if (s != null) {
//            s.setStatus(user.getStatus());
//            em.persist(s);
//            em.flush();
//        }
//    }
    public List<StaffAccountState> getStaffAccounts() throws ExistException {
        Query q = em.createQuery("SELECT a FROM StaffAcct a");
        List stateList = new ArrayList();

        if (q.getResultList().isEmpty()) {
            throw new ExistException(systemMessages.getSystemMessage("STAFF_ACCT_DOES_NOT_EXIST", selectedLocale));
        } else {
            for (Object o : q.getResultList()) {
                StaffAccountEntity a = (StaffAccountEntity) o;
                StaffAccountState staffAccountState = new StaffAccountState(
                        a.getId(),
                        a.getUsername(),
                        a.getPassword(),
                        a.getCreationDate(),
                        a.getPasswordChangeDate(),
                        a.getActivationStatus(),
                        a.getUserAccessRights(),
                        a.getStaff(),
                        a.getUserRole());
                stateList.add(staffAccountState);
            }
        }
        return stateList;
    }

//    public List<StaffAccountState> getStaffAccounts() throws ExistException {
//        Query q = em.createQuery("SELECT a FROM StaffAcct a");
//        Set stateSet = new HashSet();
//
//        if (q.getResultList().isEmpty()) {
//            throw new ExistException(systemMessages.getSystemMessage("STAFF_ACCT_DOES_NOT_EXIST", selectedLocale));
//        }
//        else {
//            for (Object o: q.getResultList()) {
//                StaffAccountEntity a = (StaffAccountEntity)o;
//                StaffAccountState staffAccountState = new StaffAccountState(
//                    a.getId(),
//                    a.getUsername(),
//                    a.getPassword(),
//                    a.getCreationDate(),
//                    a.getPasswordChangeDate(),
//                    a.getStatus(),
//                    a.getAccessRights(),
//                    a.getStaff());
//                stateSet.add(staffAccountState);
//            }
//        }
//        return stateSet;
//    }
//    public Set<StudentDetailsState> getStudentOrStudentsByName(String name)
//            throws ExistException {
//        Set stateSet = new HashSet();
//        StudentDetailsState sdState = null;
//
//        // find name in database before creation
//        Query q = em.createQuery("SELECT s FROM Student s WHERE s.name = :sName");
//        q.setParameter("sName", name);
//
//        if (q.getResultList().isEmpty()) {
//            throw new ExistException("No such student found in database!");
//        }
//        else {
//            // only 1 person with the specified name
//            if (q.getResultList().size() == 1) {
//                StudentEntity s = (StudentEntity)q.getSingleResult();
//                sdState = new StudentDetailsState(
//                        s.getStdId(), s.getName(),
//                        s.getAddress().getAddId(),
//                        s.getAddress().getAddressLine1(),
//                        s.getAddress().getAddressLine2(),
//                        s.getAddress().getPostalCode(),
//                        s.getContactNumber().getCttId(),
//                        s.getContactNumber().getPhoneNumber());
//                stateSet.add(sdState);  // add only 1
//            }
//            // if 2 or more people have the same name, return the list for user to choose
//            else if (q.getResultList().size() > 1) {
//                for (int i = 0; i < q.getResultList().size(); i++) {
//                    StudentEntity s = (StudentEntity)q.getResultList().get(i);
//                    sdState = new StudentDetailsState(
//                            s.getStdId(), s.getName(),
//                            s.getAddress().getAddId(),
//                            s.getAddress().getAddressLine1(),
//                            s.getAddress().getAddressLine2(),
//                            s.getAddress().getPostalCode(),
//                            s.getContactNumber().getCttId(),
//                            s.getContactNumber().getPhoneNumber());
//                    stateSet.add(sdState);
//                }
//            }
//        }
//        return stateSet;
//    }
    public void deleteStaffAccount(Long staffAccountId)
            throws ExistException {

        staffAccountEntity = em.find(StaffAccountEntity.class, staffAccountId);

        // tourist user account entity does not exist;
        if (staffAccountEntity == null) {
            // EXCEPTION
            throw new ExistException(systemMessages.getSystemMessage("STAFF_ACCT_DOES_NOT_EXIST", selectedLocale));
        } else {
            staffEntity = em.find(StaffEntity.class, staffAccountEntity.getStaff().getId());
//            if (staffAccountEntity.getRegistrations().size() > 0) {
//                throw new ExistException("Student has already registered.");
//            }
//
//            contactNumberEntity = studentEntity.getContactNumber();
//            addressEntity = studentEntity.getAddress();
//
//            em.remove(contactNumberEntity);
            em.remove(staffEntity);
            em.remove(staffAccountEntity);
        }
    }

    @Remove
    public void remove() {
        System.out.println("StaffAccountManagerBean:remove()");
    }

    public void verifyAcc(StakeholderEntity user) {
        StakeholderEntity s = em.find(StakeholderEntity.class, user.getId());
        if (s != null) {
            s.setActivate(user.getActivate());
            em.persist(s);
            em.flush();
        }
    }
}
